#include <cpumonitor.h>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <sstream>
#include <cstdint>
#include <regex>

CpuMonitor::CpuMonitor()
{
}

double CpuMonitor::getCpuUsage()
{
    static uint64_t lastTotal = 0, lastIdle = 0;
    std::ifstream file("/proc/stat");
    if (!file.is_open())
    {
        std::cerr << "Failed to open /proc/stat" << std::endl;
        return 0.0;
    }

    std::string line;
    std::getline(file, line);

    uint64_t user, nice, system, idle, iowait, irq, softirq;
    std::istringstream iss(line);
    std::string cpuLabel;
    iss >> cpuLabel >> user >> nice >> system >> idle >> iowait >> irq >> softirq;

    const uint64_t total = user + nice + system + idle + iowait + irq + softirq;
    const uint64_t diffTotal = total - lastTotal;
    const uint64_t diffIdle = idle - lastIdle;

    lastTotal = total;
    lastIdle = idle;

    return (diffTotal > 0) ? (100.0 * (diffTotal - diffIdle) / diffTotal) : 0.0;
}

int CpuMonitor::getCpuCount()
{
    std::regex cpuRegex("^cpu\\d+$");

    int coreCount = 0;

    // /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
    for (const auto& entry : std::filesystem::directory_iterator("/sys/devices/system/cpu/"))
    {
        if (!entry.is_directory())
        {
            continue;
        }
        std::string folderName = entry.path().filename();
        if (std::regex_match(folderName, cpuRegex))
        {
            // std::cout << folderName <<std::endl;
            coreCount++;
        }
    }
    return coreCount;
}

double CpuMonitor::getCurCpuFreq(int cpuId, FreqUnit unit)
{
    const std::string cpuFreqFilePath = "/sys/devices/system/cpu/cpu" + std::to_string(cpuId) + "/cpufreq/scaling_cur_freq";

    std::ifstream file(cpuFreqFilePath);
    if (!file.is_open())
    {
        std::cerr << "Failed to open " + cpuFreqFilePath << std::endl;
        return -1.0; 
    }

    double freq = 0;

    if (!(file >> freq)) {  
        std::cerr << "Failed to parse frequency from " + cpuFreqFilePath << std::endl;  
        return -1.0;  
    }

    if (unit == FreqUnit::GHZ)
    {
        return freq * 0.000001;
    }
    else if (unit == FreqUnit::MHZ)
    {
        return freq * 0.001;
    }
    else
    {
        return freq;
    }
}

double CpuMonitor::getAvgCpuFreq(FreqUnit unit)
{
    int coreCount = getCpuCount();
    double sum = 0;

    for (int i = 0; i < coreCount; i++)
    {
        sum += getCurCpuFreq(i, unit);
    }
    return sum / coreCount;
}

